package com.zmn.oms.dubbo.impl.zmn.order;

import com.google.common.collect.Lists;
import com.zmn.base.channel.common.dro.ChannelDRO;
import com.zmn.base.channel.dubbo.interfaces.channel.ChannelListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.oms.business.interfaces.work.OrderWorkListBService;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.enums.EncryptFieldTypeEnum;
import com.zmn.oms.dubbo.dto.zmn.order.OrderListDetailDRO;
import com.zmn.oms.dubbo.dto.zmn.order.OrderListPageDRO;
import com.zmn.oms.dubbo.dto.zmn.order.factory.FcOrderWorkListServiceItemDRO;
import com.zmn.oms.model.entity.work.OrderWorkQuery;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.oms.services.interfaces.orderencrypt.OrderEncryptService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 类描述： 订单 remote
 *
 * @author yule
 * @date 2020/5/11 17:19
 */
public abstract class OrderWorkListBaseRemoteService {

    static final String TAG = "啄木鸟-列表订单";

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    protected OrderWorkListBService orderWorkListBService;
    @Autowired
    protected ZsOrderWorkQueryBService zsOrderWorkQueryBService;
    @Autowired
    protected OrderEncryptService orderEncryptService;

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    private ChannelListRemoteService channelListRemoteService;

    /**
     * 列表查询
     *
     * @param query
     * @return
     */
    public ResponseDTO<OrderListPageDRO> listOrder(OrderWorkQuery query) {

        // 处理查询条件
        zsOrderWorkQueryBService.processWorkQuery(query);
        // 查询
        List<EsOrderWork> esOrderWorks = orderWorkListBService.listPageOrderWorkByQuery(query);
        // 解密电话和地址
        orderEncryptService.batchDecryptEsOrderWork(esOrderWorks, EncryptFieldTypeEnum.USER_TELPHONE, EncryptFieldTypeEnum.USER_ADDRESS);

        // 转 vo
        List<OrderListDetailDRO> list = Lists.newArrayList();

        esOrderWorks.forEach((esOrderWork -> {
            OrderListDetailDRO vo = BeanMapper.map(esOrderWork, OrderListDetailDRO.class);
            vo.setContactName(esOrderWork.getContact().getContactName());
            vo.setContactPhone(esOrderWork.getContact().getPhone());
            vo.setUserName(esOrderWork.getContact().getUserName());
            vo.setPhone(esOrderWork.getContact().getPhone());
            vo.setAddress(esOrderWork.getContact().getAddress());
            vo.setStreet(esOrderWork.getContact().getStreet());
            vo.setProvinceName(esOrderWork.getProvinceName());
            vo.setCityName(esOrderWork.getCityName());
            vo.setCountyName(esOrderWork.getCountyName());
            vo.setProvinceId(esOrderWork.getProvinceId());
            vo.setCityId(esOrderWork.getCityId());
            vo.setCountyId(esOrderWork.getCountyId());
            vo.setWorkId(esOrderWork.getId());
            vo.setWorkType(esOrderWork.getType());
            vo.setDiscountAmount(esOrderWork.getDiscountAmount());
            vo.setChannelName(esOrderWork.getChannelName());
            vo.setBizType(esOrderWork.getBizType());
            vo.setServiceProviderAmount(esOrderWork.getServiceProviderRewardAmount());

            if (Objects.nonNull(esOrderWork.getSuspendTime())) {
                vo.setSuspendStatus(GlobalConsts.YES);
            }

            if (Objects.nonNull(esOrderWork.getShopOrder())) {
                vo.setShopName(esOrderWork.getShopOrder().getShopName());
            }

            if (Objects.nonNull(esOrderWork.getFactoryOrder())) {
                vo.setRemoteAmount(Optional.ofNullable(esOrderWork.getFactoryOrder().getRemoteAmount()).orElse(0));
            }

            if (Objects.equals(GlobalConsts.PLAT_MARK_SAAS, esOrderWork.getPlatWork())) {
                convertStatus(vo, esOrderWork.getStatus(), esOrderWork.getResultStatus());
            }

            // 处理预约超时
            convertDutyTimeOut(vo, esOrderWork);

            // 处理即将预约超时、已超时
            processTimeOut(vo, esOrderWork);

            // 渠道别名
            ResponseDTO<ChannelDRO> channelResponseDTO = channelListRemoteService.getByChannelId(esOrderWork.getChannelId());
            if(channelResponseDTO.isSuccess() && channelResponseDTO.getData() != null){
                vo.setAnotherName(channelResponseDTO.getData().getAnotherName());
            }

            vo.setServiceItemList(BeanMapper.mapList(esOrderWork.getServiceItemList(), FcOrderWorkListServiceItemDRO.class));

            list.add(vo);
        }));

        OrderListPageDRO pageDRO = new OrderListPageDRO();
        pageDRO.setTotalCount(query.getTotalCount());
        pageDRO.setList(list);

        return ResponseDTO.success(pageDRO, GlobalConsts.SUCCESS_MSG);
    }

    /**
     * SAAS服务商状态转换
     *
     * @param vo
     * @param status
     * @param resultStatus
     */
    private void convertStatus(OrderListDetailDRO vo, Integer status, Integer resultStatus) {
        //1.待派单--》已分单
        List<Integer> supportStatusList = Lists.newArrayList(OrderStatusConsts.WORK_STATUS_ASSIGN);
        List<Integer> supportResultStatusList = Lists.newArrayList(OrderStatusConsts.WORK_RESULT_DOING);

        //2.服务中--》已派单、已领单、已上门
        List<Integer> supportStatusList1 = Lists.newArrayList(OrderStatusConsts.WORK_STATUS_DISTRIBUTE, OrderStatusConsts.WORK_STATUS_TAKE, OrderStatusConsts.WORK_STATUS_VISIT);

        //3.已完成

        //4.已取消 未完成+结果-弃单或失败
        //supportStatusList<已完成
        List<Integer> supportResultStatusList1 = Lists.newArrayList(OrderStatusConsts.WORK_RESULT_FAIL, OrderStatusConsts.WORK_RESULT_DISCARD);

        boolean statusSupport = supportStatusList.contains(status);

        boolean resultStatusSupport = supportResultStatusList.contains(resultStatus);//进行中
        if (resultStatusSupport && statusSupport) {
            vo.setStatusName("待派单");
        }

        boolean statusSupport1 = supportStatusList1.contains(status);
        if (resultStatusSupport && statusSupport1) {
            vo.setStatusName("服务中");
        }

        boolean statusSupport2 = status < OrderStatusConsts.WORK_STATUS_COMPLETE;
        boolean resultStatusSupport2 = supportResultStatusList1.contains(resultStatus);
        if (statusSupport2 && resultStatusSupport2) {
            vo.setStatusName("已取消");
        }
    }


    // 处理预约超时
    // 预约超时：下单两小时未预约上门时间且工单状态处于“已录入、已确认、已分单、已派单、已领单”且订单为进行中
    private void convertDutyTimeOut(OrderListDetailDRO vo, EsOrderWork esOrderWork) {

        // 结果-进行中，已派单、已上门可操作
        List<Integer> supportStatusList = Lists.newArrayList(
                OrderStatusConsts.WORK_STATUS_INPUT,
                OrderStatusConsts.WORK_STATUS_CONFIRM,
                OrderStatusConsts.WORK_STATUS_ASSIGN,
                OrderStatusConsts.WORK_STATUS_DISTRIBUTE,
                OrderStatusConsts.WORK_STATUS_TAKE);

        List<Integer> supportResultStatusList = Lists.newArrayList(OrderStatusConsts.WORK_RESULT_DOING);
        boolean resultStatusSupport = supportResultStatusList.contains(esOrderWork.getResultStatus());
        boolean statusSupport = supportStatusList.contains(esOrderWork.getStatus());

        boolean isTimeout = DateUtil.getTimespan(esOrderWork.getReceiveTime().getTime(), DateUtil.getNowTimestampMillis(), DateUtil.UNIT_SECOND) > (2 * 60 * 60);

        boolean isNotExistDutyTime = Objects.isNull(esOrderWork.getDutyTime());
        if (resultStatusSupport && statusSupport && isTimeout && isNotExistDutyTime) {
            vo.setDutyTimeIsTimeout(true);
        }
    }

    public void processTimeOut(OrderListDetailDRO vo, EsOrderWork esOrderWork){

        // 即将预约超时 前置条件
        // 1.下单无预约时间
        // 2.有签收时间（若无则取下单时间）（比较挂起时间或取消时间是否大于签收时间60min小于119分钟,若没在这个时间段进行这两种操作，即定义为即将预约超时）
        // 3.若签收时间大于当天18点，则比较时间为次日 9:00-9:59

        // 已超时 前置条件
        // 1.下单无预约时间  2.有签收时间（若无则取下单时间）（比较挂起时间或取消时间是否大于签收时间120分钟）
        // 3.若签收时间大于当天18点，则比较时间为次日 10:00
        if(Objects.nonNull(esOrderWork.getDutyTime())){
            vo.setPreDutyTimeOut(GlobalConsts.NO);
            vo.setAlreadyPreDutyTimeOut(GlobalConsts.NO);
        }else {
            // 挂起时间、取消时间
            Date suspendTime = esOrderWork.getSuspendTime();
            Date cancelTime = esOrderWork.getCancelTime();

            // 所比较时间
            Date compareTime = Objects.nonNull(esOrderWork.getSignForTime()) ? esOrderWork.getSignForTime():esOrderWork.getInputTime();
            // 签收时间当日18点
            Date dateStart = this.getSixPMDate(compareTime);
            long sixPM = DateUtil.getTimespan(dateStart, compareTime, DateUtil.UNIT_SECOND);
            boolean result = false;
            long alreadyTimeOut = 0;

            if(sixPM < 0){
                // 判断当前时间如果大于 签收时间60min小于119分钟 无挂起与取消操作 则为超时
                long timespan = DateUtil.getTimespan(DateUtil.addMinute(compareTime, 120), DateUtil.getNow(), DateUtil.UNIT_SECOND);
                boolean preTimeOut = DateUtil.isBetween(DateUtil.addMinute(compareTime, 60), DateUtil.addMinute(compareTime, 119), DateUtil.getNow());
                if (preTimeOut) {
                    result = Objects.isNull(suspendTime) && Objects.isNull(cancelTime);
                }
                if (timespan > 0) {
                    alreadyTimeOut = (Objects.isNull(suspendTime) && Objects.isNull(cancelTime)) ? -1 : 0;
                }
                vo.setPreDutyTimeOut(result ? GlobalConsts.YES:GlobalConsts.NO);
                vo.setAlreadyPreDutyTimeOut(alreadyTimeOut < 0 ? GlobalConsts.YES:GlobalConsts.NO);
            }else {
                // 次日 9:00-9:59
                Date tomorrowDate = this.getTomorrowDate(compareTime);
                // 判断当前时间如果大于 签收时间60min小于119分钟 无挂起与取消操作 则为超时
                long timespan = DateUtil.getTimespan(DateUtil.addMinute(tomorrowDate, 120), DateUtil.getNow(), DateUtil.UNIT_SECOND);
                boolean preTimeOut = DateUtil.isBetween(DateUtil.addMinute(tomorrowDate, 60), DateUtil.addMinute(tomorrowDate, 119), DateUtil.getNow());
                if (preTimeOut) {
                    result = Objects.isNull(suspendTime) && Objects.isNull(cancelTime);
                }
                if (timespan > 0) {
                    alreadyTimeOut = (Objects.isNull(suspendTime) && Objects.isNull(cancelTime)) ? -1 : 0;
                }
                vo.setPreDutyTimeOut(result ? GlobalConsts.YES:GlobalConsts.NO);
                vo.setAlreadyPreDutyTimeOut(alreadyTimeOut < 0 ? GlobalConsts.YES:GlobalConsts.NO);
            }
            // 两种超时标识显示一种
            if(Objects.equals(vo.getAlreadyPreDutyTimeOut(),GlobalConsts.YES)){
                vo.setPreDutyTimeOut(GlobalConsts.NO);
            }
        }
    }

    // 获取当天18点日期
    private Date getSixPMDate(Date baseTime) {
        if (baseTime == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(baseTime);
        calendar.set(Calendar.HOUR_OF_DAY, 18);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    // 获取次日8点日期
    private Date getTomorrowDate(Date baseTime) {
        if (baseTime == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(baseTime);
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 8);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

}
